package com.jack.xmlparser.parser;

import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributeListImpl;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;

import com.jack.xmlparser.iui.BaseParser;
import com.jack.xmlparser.util.Book;

@SuppressWarnings("deprecation")
public class SaxParserForBook implements BaseParser {

	@Override
	public List<Object> parserToObject(InputStream is) {
		// TODO Auto-generated method stub
		try {
			SAXParserFactory mFactory = SAXParserFactory.newInstance();
			SAXParser mParser = mFactory.newSAXParser();
			ParserHandler mhandler = new ParserHandler();
			mParser.parse(is, mhandler);
			return mhandler.getBooks();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public String parserToXml(List<Object> list) {
		// TODO Auto-generated method stub
		try {
			SAXTransformerFactory mFactory = (SAXTransformerFactory) TransformerFactory.newInstance();
			TransformerHandler mHandler = mFactory.newTransformerHandler();
			Transformer mTransformer = mHandler.getTransformer();
			mTransformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			mTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
			mTransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
			
			StringWriter mWriter = new StringWriter();
			StreamResult mResult = new StreamResult(mWriter);
			mHandler.setResult(mResult);
			
			String uri = "";
			String localName = "";
			
			mHandler.startDocument();
			mHandler.startElement(uri, localName, "books", null);
			
			AttributesImpl mAttrs = new AttributesImpl();
			char[] ch = null;
			
			for (Object o : list) {
				if (o instanceof Book) {
					Book mBook = (Book) o;
					
					mAttrs.addAttribute(uri, localName, "id", "string", String.valueOf(mBook.getId()));
					mHandler.startElement(uri, localName, "book", mAttrs);
					
					mHandler.startElement(uri, localName, "name", null);
					ch = mBook.getName().toCharArray();
					mHandler.characters(ch, 0, ch.length);
					mHandler.endElement(uri, localName, "name");
					
					mHandler.startElement(uri, localName, "price", null);
					ch = String.valueOf(mBook.getPrice()).toCharArray();
					mHandler.characters(ch, 0, ch.length);
					mHandler.endElement(uri, localName, "price");
					
					mHandler.endElement(uri, localName, "book");
					
					mAttrs.clear();
				}
			}
			mHandler.endElement(uri, localName, "books");
			mHandler.endDocument();
			
			return mWriter.toString();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			return null;
		}
	}

	
	private class ParserHandler extends DefaultHandler {

		private List<Object> mBooks;
		private Book mBook;
		private StringBuilder mStrBuilder;
		
		public List<Object> getBooks() {
			return mBooks;
		}

		@Override
		public void startDocument() throws SAXException {
			// TODO Auto-generated method stub
			super.startDocument();
			mBooks = new ArrayList<Object>();
			mStrBuilder = new StringBuilder();
		}

		@Override
		public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
			// TODO Auto-generated method stub
			super.startElement(uri, localName, qName, attributes);
			if (localName.equals("book")) {
				mBook = new Book();
				if (attributes != null && attributes.getLength() > 0) {
					for (int i = 0; i < attributes.getLength(); i++) {
						if (attributes.getLocalName(i).equals("id")) {
							mBook.setId(Integer.parseInt(attributes.getValue(i)));
						}
					}
				}
			}
			mStrBuilder.setLength(0);
		}

		@Override
		public void characters(char[] ch, int start, int length) throws SAXException {
			// TODO Auto-generated method stub
			super.characters(ch, start, length);
			mStrBuilder.append(ch, start, length);
		}
		
		@Override
		public void endElement(String uri, String localName, String qName) throws SAXException {
			// TODO Auto-generated method stub
			super.endElement(uri, localName, qName);
			if (localName.equals("name")) {
				mBook.setName(mStrBuilder.toString());
			} else if (localName.equals("price")) {
				mBook.setPrice(Float.parseFloat(mStrBuilder.toString()));
			} else {
				if (!localName.equals("books")) {
					mBooks.add(mBook);
				}
			}
		}
		
		@Override
		public void endDocument() throws SAXException {
			// TODO Auto-generated method stub
			super.endDocument();
			mBook = null;
			mStrBuilder = null;
		}
		
	}
	
}
